package monitor

import (
	"bytes"
	"fmt"
	"gitee.com/igolang/imoney/internal/app/system/entities"
	"gitee.com/igolang/imoney/internal/app/system/entities/constants"
	"gitee.com/igolang/imoney/internal/app/system/services/dict"
	commonEntities "gitee.com/igolang/imoney/internal/common/entities"
	"gitee.com/igolang/imoney/internal/common/httpResp"
	commonTools "gitee.com/igolang/imoney/internal/common/tools"
	"gitee.com/igolang/imoney/internal/common/tools/cronJob"
	"gitee.com/igolang/imoney/internal/core/client"
	"gitee.com/igolang/imoney/internal/core/logger"
	"gitee.com/igolang/imoney/internal/models/dao"
	"gitee.com/igolang/imoney/internal/models/model"
	"gitee.com/igolang/pkg/xjson"
	"gitee.com/igolang/pkg/xutils"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
	"gorm.io/gen"
)

var JobLog = &jobLog{}

type jobLog struct{}

func (s *jobLog) List(ctx *gin.Context) (*commonEntities.ListResp, error) {
	var req entities.JobLogPageListReq
	if err := ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	req.Page()
	conds := s.formatPageListConds(req)
	total, err := dao.SysJobLog.Where(conds...).Count()
	if err != nil {
		return nil, err
	}
	result := &commonEntities.ListResp{
		Total: total,
		Rows:  make([]*model.SysJobLog, 0),
	}
	if total == 0 {
		return result, nil
	}
	rows, err := dao.SysJobLog.Where(conds...).Limit(req.PageSize).Offset(req.Offset).Order(dao.SysJobLog.JobLogID.Desc()).Find()
	if err != nil {
		return nil, err
	}
	result.Rows = rows
	return result, nil
}

func (s *jobLog) Export(ctx *gin.Context) (*bytes.Buffer, error) {
	var req entities.JobLogPageListReq
	if err := ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	req.Page()
	conds := s.formatPageListConds(req)
	rows, err := dao.SysJobLog.Where(conds...).Rows()
	if err != nil {
		return nil, err
	}
	head := []string{"日志序号", "任务名称", "任务组名", "调用目标字符串", "日志信息", "执行状态", "异常信息", "执行结果"}
	data := [][]string{head}
	dc := client.DB()
	statusOption, _ := dict.Get("sys_common_status")
	groupOption, _ := dict.Get("sys_job_group")
	for rows.Next() {
		var row model.SysJobLog
		if dc.ScanRows(rows, &row) == nil {
			data = append(data, []string{
				cast.ToString(row.JobLogID),
				row.JobName,
				dict.LabelOptions(groupOption, row.JobGroup),
				row.InvokeTarget,
				row.JobMessage,
				dict.LabelOptions(statusOption, row.Status),
				row.ExceptionInfo,
				row.Result,
			})
		}
	}
	fh := xutils.CreateExcelFileWithData(data)
	defer fh.Close()
	return fh.WriteToBuffer()
}

func (s *jobLog) Delete(ctx *gin.Context) error {
	ids := commonTools.String2Int64s(ctx.Param("ids"))
	if len(ids) == 0 {
		return httpResp.ErrorCode(httpResp.ErrCodeInvalidParams)
	}
	_, err := dao.SysJobLog.Where(dao.SysJobLog.JobLogID.In(ids...)).Delete()
	return err
}

func (s *jobLog) Clean() error {
	_, err := dao.SysJobLog.Where(dao.SysJobLog.JobLogID.Gt(0)).Delete()
	return err
}

func (s *jobLog) formatPageListConds(req entities.JobLogPageListReq) []gen.Condition {
	conds := make([]gen.Condition, 0)
	req.Page()
	if req.JobName != "" {
		conds = append(conds, dao.SysJobLog.JobName.Like(`%`+req.JobName+`%`))
	}
	if req.JobGroup != "" {
		conds = append(conds, dao.SysJobLog.JobGroup.Eq(req.JobGroup))
	}
	if req.Status != "" {
		conds = append(conds, dao.SysJobLog.Status.Eq(req.Status))
	}
	if !req.BT.IsZero() && !req.ET.IsZero() {
		conds = append(conds, dao.SysJobLog.CreateTime.Between(req.BT, req.ET))
	}

	return conds
}

func (s *jobLog) AddJobLog(result *cronJob.Result) {
	// 获取任务信息
	row, err := dao.SysJob.Where(dao.SysJob.InvokeTarget.Eq(result.Key)).Take()
	if err != nil {
		logger.Log().Error("获取任务信息出错", "err", err, "jobResult", result)
		return
	}

	data := &model.SysJobLog{
		JobName:      row.JobName,
		JobGroup:     row.JobGroup,
		InvokeTarget: row.InvokeTarget,
		JobMessage:   fmt.Sprintf("%s 总共耗时：%v", row.JobName, result.EndTime.Time().Sub(result.StartTime.Time())),
		Status:       constants.OkStatus,
		CreateTime:   result.StartTime,
	}
	if result.Err != nil || result.Exception != nil {
		data.Status = "1"
		data.ExceptionInfo = fmt.Sprintf("err: %v, stack:%+v", result.Err, result.Exception)
	}

	b, err := xjson.Marshal(result)
	if err != nil {
		logger.Log().Error("marshal result err", "err", err, "jobResult", result)
		return
	}
	data.Result = string(b)
	err = dao.SysJobLog.Create(data)
	if err != nil {
		logger.Log().Error("新增任务日志出错", "err", err, "jobResult", result)
	}
}
